/*
 * Copyright (C) 2010,2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

/*
 * Prototypes
 */
#if PROTO
static void
cp_div2_cp_i(c_t *u, c_t *v, eint32_t w, eint32_t m);

static void
cp_div2_c_cp(c_t *u, c_t v, c_t *w, eint32_t m);

static void
cp_div2_cp_cp(c_t *u, c_t *v, c_t *w, eint32_t m);

static void
sp_div2_sp_i(s_t *u, s_t *v, eint32_t w, eint32_t m);

static void
sp_div2_s_sp(s_t *u, s_t v, s_t *w, eint32_t m);

static void
sp_div2_sp_sp(s_t *u, s_t *v, s_t *w, eint32_t m);

static void
ip_div2_ip_i(i_t *u, i_t *v, eint32_t w, eint32_t m);

static void
ip_div2_i_ip(i_t *u, i_t v, i_t *w, eint32_t m);

static void
ip_div2_ip_ip(i_t *u, i_t *v, i_t *w, eint32_t m);

static void
lp_div2_lp_i(l_t *u, l_t *v, eint32_t w, eint32_t m);

static void
lp_div2_l_lp(l_t *u, l_t v, l_t *w, eint32_t m);

static void
lp_div2_lp_lp(l_t *u, l_t *v, l_t *w, eint32_t m);

static void
fp_div2_fp_i(f_t *u, f_t *v, eint32_t w, eint32_t m);

static void
fp_div2_f_fp(f_t *u, f_t v, f_t *w, eint32_t m);

static void
fp_div2_fp_fp(f_t *u, f_t *v, f_t *w, eint32_t m);

static void
dp_div2_dp_i(d_t *u, d_t *v, eint32_t w, eint32_t m);

static void
dp_div2_d_dp(d_t *u, d_t v, d_t *w, eint32_t m);

static void
dp_div2_dp_dp(d_t *u, d_t *v, d_t *w, eint32_t m);

static void
div2_i_i(o_t *u, eint_t a, eint32_t b);

static void
div2_d_i(o_t *u, efloat_t a, eint32_t b);

static void
div2_z_i(o_t *u, empz_t a, eint32_t b);

static void
div2_q_i(o_t *u, empq_t a, eint32_t b);

static void
div2_r_i(o_t *u, empr_t a, eint32_t b);

static void
div2_dd_i(o_t *u, ecdd_t a, eint32_t b);

static void
div2_qq_i(o_t *u, ecqq_t a, eint32_t b);

static void
div2_cc_i(o_t *u, empc_t a, eint32_t b);

static void
vo_div2_i_vo(vo_t *u, eint_t v, vo_t *w, eint32_t m);

static void
vo_div2_d_vo(vo_t *u, efloat_t v, vo_t *w, eint32_t m);

static void
vo_div2_z_vo(vo_t *u, empz_t v, vo_t *w, eint32_t m);

static void
vo_div2_q_vo(vo_t *u, empq_t v, vo_t *w, eint32_t m);

static void
vo_div2_r_vo(vo_t *u, empr_t v, vo_t *w, eint32_t m);

static void
vo_div2_dd_vo(vo_t *u, ecdd_t v, vo_t *w, eint32_t m);

static void
vo_div2_qq_vo(vo_t *u, ecqq_t v, vo_t *w, eint32_t m);

static void
vo_div2_cc_vo(vo_t *u, empc_t v, vo_t *w, eint32_t m);

static void
vo_div2_vo_i(vo_t *u, vo_t *v, eint32_t w, eint32_t m);

static void
vo_div2_vo_vo(vo_t *u, vo_t *v, vo_t *w, eint32_t m);

static void
o_div2_o_i(o_t *u, o_t *v, eint32_t w);
#endif

/*
 * Implementation
 */
#if CODE
void
evector_div2_int32(evector_t *a, eint32_t b, etype_t t)
{
    eint32_t	 l;
    evector_t	*v;
    etype_t	 vt;
    v_enter();

    l = a->length;
    v_check(2);
    if (b > 32767 || b < -32767)
	vt = match(t_int32, t, 0, 0);
    else if (b > 127 || b < -127)
	vt = match(t_int16, t, 0, 0);
    else
	vt = match(t_int8, t, 0, 0);
    if (vt != t)
	a = coerce(a, t, vt);
    v = create(a, vt);
    switch (vt) {
	case t_int8:
	    cp_div2_cp_i(v->v.obj, a->v.obj, b, l);
	    break;
	case t_int16:
	    sp_div2_sp_i(v->v.obj, a->v.obj, b, l);
	    break;
	case t_int32:
	    ip_div2_ip_i(v->v.obj, a->v.obj, b, l);
	    break;
	case t_int64:
	    lp_div2_lp_i(v->v.obj, a->v.obj, b, l);
	    break;
	case t_float32:
	    fp_div2_fp_i(v->v.obj, a->v.obj, b, l);
	    break;
	case t_float64:
	    dp_div2_dp_i(v->v.obj, a->v.obj, b, l);
	    break;
	default:
	    vo_div2_vo_i(v->v.obj, a->v.obj, b, l);
	    break;
    }
    v_leave();
}

void
evector_int_div2(eint_t a, evector_t *b, etype_t t)
{
    eint32_t	 l;
    evector_t	*v;
    etype_t	 vt;
    v_enter();

    l = b->length;
    v_check(2);
    if (a > 2147483647 || a < -2147483647)
	vt = match(t_int64, t, 0, 0);
    else if (a > 32767 || a < -32767)
	vt = match(t_int32, t, 0, 0);
    else if (a > 127 || a < -127)
	vt = match(t_int16, t, 0, 0);
    else
	vt = match(t_int8, t, 0, 0);
    if (vt != t)
	b = coerce(b, t, vt);
    v = create(b, vt);
    switch (vt) {
	case t_int8:
	    cp_div2_c_cp(v->v.obj, a, b->v.obj, l);
	    break;
	case t_int16:
	    sp_div2_s_sp(v->v.obj, a, b->v.obj, l);
	    break;
	case t_int32:
	    ip_div2_i_ip(v->v.obj, a, b->v.obj, l);
	    break;
	case t_int64:
	    lp_div2_l_lp(v->v.obj, a, b->v.obj, l);
	    break;
	case t_float32:
	    fp_div2_f_fp(v->v.obj, a, b->v.obj, l);
	    break;
	case t_float64:
	    dp_div2_d_dp(v->v.obj, a, b->v.obj, l);
	    break;
	default:
	    vo_div2_i_vo(v->v.obj, a, b->v.obj, l);
	    break;
    }
    v_leave();
}

void
evector_float_div2(efloat_t a, evector_t *b, etype_t t)
{
    eint32_t	 l;
    evector_t	*v;
    etype_t	 vt;
    v_enter();

    l = b->length;
    v_check(2);
    vt = match(t_float, t, 0, 0);
    if (vt != t)
	b = coerce(b, t, vt);
    v = create(b, vt);
    switch (vt) {
	case t_float64:
	    dp_div2_d_dp(v->v.obj, a, b->v.obj, l);
	    break;
	default:
	    vo_div2_d_vo(v->v.obj, a, b->v.obj, l);
	    break;
    }
    v_leave();
}

void
evector_mpz_div2(empz_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_z_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_mpq_div2(empq_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_q_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_mpr_div2(empr_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_r_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_cdd_div2(ecdd_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_dd_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_cqq_div2(ecqq_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_qq_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_mpc_div2(empc_t a, evector_t *b, etype_t t)
{
    evector_t	*v;
    v_enter();

    v_check(2);
    if (t != t_void)
	b = coerce(b, t, t_void);
    v = create(b, t_void);
    vo_div2_cc_vo(v->v.obj, a, b->v.obj, v->length);
    v_leave();
}

void
evector_div2(evector_t *a, evector_t *b, etype_t at, etype_t bt)
{
    eint32_t	l;
    evop_t	o;
    v_enter();

    setup(&o, a, b, at, bt, 0, 0);
    l = o.r->length;
    switch (o.t) {
	case t_int8:
	    cp_div2_cp_cp(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	case t_int16:
	    sp_div2_sp_sp(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	case t_int32:
	    ip_div2_ip_ip(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	case t_int64:
	    lp_div2_lp_lp(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	case t_float32:
	    fp_div2_fp_fp(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	case t_float64:
	    dp_div2_dp_dp(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
	default:
	    vo_div2_vo_vo(o.r->v.obj, o.a->v.obj, o.b->v.obj, l);
	    break;
    }
    v_leave();
}

static void
cp_div2_cp_i(c_t *u, c_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = *v++ >> w;
}

static void
cp_div2_c_cp(c_t *u, c_t v, c_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = v >> s;
	else
	    *u++ = v << s;
    }
}

static void
cp_div2_cp_cp(c_t *u, c_t *v, c_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = *v++ >> s;
	else
	    *u++ = *v++ << s;
    }
}

static void
sp_div2_sp_i(s_t *u, s_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = *v++ >> w;
}

static void
sp_div2_s_sp(s_t *u, s_t v, s_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = v >> s;
	else
	    *u++ = v << s;
    }
}

static void
sp_div2_sp_sp(s_t *u, s_t *v, s_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = *v++ >> s;
	else
	    *u++ = *v++ << s;
    }
}

static void
ip_div2_ip_i(i_t *u, i_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = *v++ >> w;
}

static void
ip_div2_i_ip(i_t *u, i_t v, i_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = v >> s;
	else
	    *u++ = v << s;
    }
}

static void
ip_div2_ip_ip(i_t *u, i_t *v, i_t *w, eint32_t m)
{
    eint32_t	s;

    while (m--) {
	if ((s = *w++) >= 0)
	    *u++ = *v++ >> s;
	else
	    *u++ = *v++ << s;
    }
}

static void
lp_div2_lp_i(l_t *u, l_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = *v++ >> w;
}

static void
lp_div2_l_lp(l_t *u, l_t v, l_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	if ((s = get_i_shift(*w)) >= 0) {
	    if (s < 64)		*u = v >> s;
	    else		*u = 0;
	}
	else if (s > -64)	*u = v << -s;
	else			*u = 0;
    }
}

static void
lp_div2_lp_lp(l_t *u, l_t *v, l_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, v++, w++) {
	if ((s = get_i_shift(*w)) >= 0) {
	    if (s < 64)		*u = *v >> s;
	    else		*u = 0;
	}
	else if (s > -64)	*u = *v << -s;
	else			*u = 0;
    }
}

static void
fp_div2_fp_i(f_t *u, f_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = ef_div2_d_i(*v++, w);
}

static void
fp_div2_f_fp(f_t *u, f_t v, f_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	s = get_d_shift(*w);
	*u = ef_div2_d_i(v, s);
    }
}

static void
fp_div2_fp_fp(f_t *u, f_t *v, f_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, v++, w++) {
	s = get_d_shift(*w);
	*u = ef_div2_d_i(*v, s);
    }
}

static void
dp_div2_dp_i(d_t *u, d_t *v, eint32_t w, eint32_t m)
{
    while (m--)
	*u++ = ef_div2_d_i(*v++, w);
}

static void
dp_div2_d_dp(d_t *u, d_t v, d_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	s = get_d_shift(*w);
	*u = ef_div2_d_i(v, s);
    }
}

static void
dp_div2_dp_dp(d_t *u, d_t *v, d_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, v++, w++) {
	s = get_d_shift(*w);
	*u = ef_div2_d_i(*v, s);
    }
}

static void
div2_i_i(o_t *u, eint_t a, eint32_t b)
{
    if (b) {
	if ((a = eq_div2_i_i(thr_qr, a, b)) == MININT)
	    set_q(thr_qr);
	else
	    set_i(a);
    }
    else
	set_i(a);
}

static void
div2_d_i(o_t *u, efloat_t a, eint32_t b)
{
    set_d(ef_div2_d_i(a, b));
}

static void
div2_z_i(o_t *u, empz_t a, eint32_t b)
{
    switch (eq_div2_z_i(thr_qr, a, b)) {
	case 0:
	    set_q(thr_qr);
	    break;
	case 1:
	    set_i(empz_get_i(thr_zr));
	    break;
	default:
	    set_z(thr_zr);
	    break;
    }
}

static void
div2_q_i(o_t *u, empq_t a, eint32_t b)
{
    switch (eq_div2_q_i(thr_qr, a, b)) {
	case 0:
	    set_q(thr_qr);
	    break;
	case 1:
	    set_i(empz_get_i(thr_zr));
	    break;
	default:
	    set_z(thr_zr);
	    break;
    }
}

static void
div2_r_i(o_t *u, empr_t a, eint32_t b)
{
    er_div2_r_i(thr_rr, a, b);
    set_r(thr_rr);
}

static void
div2_dd_i(o_t *u, ecdd_t a, eint32_t b)
{
    set_dd(edd_div2_dd_i(a, b));
}

static void
div2_qq_i(o_t *u, ecqq_t a, eint32_t b)
{
    eqq_div2_qq_i(thr_qq, a, b);
    set_qq(thr_qq);
}

static void
div2_cc_i(o_t *u, empc_t a, eint32_t b)
{
    ecc_div2_cc_i(thr_c, a, b);
    set_cc(thr_c);
}

static void
vo_div2_vo_i(vo_t *u, vo_t *v, eint32_t w, eint32_t m)
{
    for (; m; u++, v++, m--)
	o_div2_o_i(u, v, w);
}

static void
vo_div2_i_vo(vo_t *u, eint_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_i_i(u, v, s);
		else
		    mul2_i_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_i_i(u, v, s);
		else
		    mul2_i_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_i_i(u, v, s);
		else
		    mul2_i_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
}

static void
vo_div2_d_vo(vo_t *u, efloat_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_d_i(u, v, s);
		else
		    mul2_d_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_d_i(u, v, s);
		else
		    mul2_d_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_d_i(u, v, s);
		else
		    mul2_d_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
}

static void
vo_div2_z_vo(vo_t *u, empz_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;
    ebool_t	b;

    if (unlikely((b = v == thr_zr))) {
	++thread_self->esp;
	eget_mpz(v, (thread_self->esp - thread_self->ess) - 1);
	v = thread_self->esp[-1].v.o;
    }
    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_z_i(u, v, s);
		else
		    mul2_z_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_z_i(u, v, s);
		else
		    mul2_z_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_z_i(u, v, s);
		else
		    mul2_z_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
    if (b)
	--thread_self->esp;
}

static void
vo_div2_q_vo(vo_t *u, empq_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;
    ebool_t	b;

    if (unlikely((b = v == thr_qr))) {
	++thread_self->esp;
	eget_mpq(v, (thread_self->esp - thread_self->ess) - 1);
	v = thread_self->esp[-1].v.o;
    }
    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_q_i(u, v, s);
		else
		    mul2_q_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_q_i(u, v, s);
		else
		    mul2_q_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_q_i(u, v, s);
		else
		    mul2_q_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
    if (b)
	--thread_self->esp;
}

static void
vo_div2_r_vo(vo_t *u, empr_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;
    ebool_t	b;

    if (unlikely((b = v == thr_rr))) {
	++thread_self->esp;
	eget_mpr(v, (thread_self->esp - thread_self->ess) - 1);
	v = thread_self->esp[-1].v.o;
    }
    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_r_i(u, v, s);
		else
		    mul2_r_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_r_i(u, v, s);
		else
		    mul2_r_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_r_i(u, v, s);
		else
		    mul2_r_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
    if (b)
	--thread_self->esp;
}

static void
vo_div2_dd_vo(vo_t *u, ecdd_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_dd_i(u, v, s);
		else
		    mul2_dd_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_dd_i(u, v, s);
		else
		    mul2_dd_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_dd_i(u, v, s);
		else
		    mul2_dd_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
}

static void
vo_div2_qq_vo(vo_t *u, ecqq_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;
    ebool_t	b;

    if (unlikely((b = v == thr_qq))) {
	++thread_self->esp;
	eget_cqq(v, (thread_self->esp - thread_self->ess) - 1);
	v = thread_self->esp[-1].v.o;
    }
    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_qq_i(u, v, s);
		else
		    mul2_qq_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_qq_i(u, v, s);
		else
		    mul2_qq_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_qq_i(u, v, s);
		else
		    mul2_qq_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
    if (b)
	--thread_self->esp;
}

static void
vo_div2_cc_vo(vo_t *u, empc_t v, vo_t *w, eint32_t m)
{
    eint32_t	s;
    ebool_t	b;

    if (unlikely((b = v == thr_c))) {
	++thread_self->esp;
	eget_mpc(v, (thread_self->esp - thread_self->ess) - 1);
	v = thread_self->esp[-1].v.o;
    }
    for (; m; m--, u++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		set_i(0);
		break;
	    case t_int:
		if ((s = get_i_shift(get_i(w))) >= 0)
		    div2_cc_i(u, v, s);
		else
		    mul2_cc_i(u, v, -s);
		break;
	    case t_float:
		if ((s = get_d_shift(get_d(w))) >= 0)
		    div2_cc_i(u, v, s);
		else
		    mul2_cc_i(u, v, -s);
		break;
	    case t_mpr:
		if ((s = get_r_shift(get_r(w))) >= 0)
		    div2_cc_i(u, v, s);
		else
		    mul2_cc_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
    if (b)
	--thread_self->esp;
}

static void
vo_div2_vo_vo(vo_t *u, vo_t *v, vo_t *w, eint32_t m)
{
    eint32_t	s;

    for (; m; m--, u++, v++, w++) {
	switch (eobject_type(*w)) {
	    case t_void:
		o_div2_o_i(u, v, 0);
		break;
	    case t_int:
		s = get_i_shift(get_i(w));
		if (s >= 0)
		    o_div2_o_i(u, v, s);
		else
		    o_mul2_o_i(u, v, -s);
		break;
	    case t_float:
		s = get_d_shift(get_d(w));
		if (s >= 0)
		    o_div2_o_i(u, v, s);
		else
		    o_mul2_o_i(u, v, -s);
		break;
	    case t_mpr:
		s = get_r_shift(get_r(w));
		if (s >= 0)
		    o_div2_o_i(u, v, s);
		else
		    o_mul2_o_i(u, v, -s);
		break;
	    case t_mpz:
	    case t_mpq:
		eraise_exception(except_not_a_32_bits_integer);
	    default:
		eraise_exception(except_not_a_real_number);
	}
    }
}

static void
o_div2_o_i(o_t *u, o_t *v, eint32_t w)
{
    switch (eobject_type(*v)) {
	case t_void:
	    set_i(0);
	    break;
	case t_int:
	    div2_i_i(u, get_i(v), w);
	    break;
	case t_float:
	    div2_d_i(u, get_d(v), w);
	    break;
	case t_mpz:
	    div2_z_i(u, get_z(v), w);
	    break;
	case t_mpq:
	    div2_q_i(u, get_q(v), w);
	    break;
	case t_mpr:
	    div2_r_i(u, get_r(v), w);
	    break;
	case t_cdd:
	    div2_dd_i(u, get_dd(v), w);
	    break;
	case t_cqq:
	    div2_qq_i(u, get_qq(v), w);
	    break;
	case t_mpc:
	    div2_cc_i(u, get_cc(v), w);
	    break;
	default:
	    eraise_exception(except_not_a_real_number);
    }
}
#endif
